package dse;

import java.util.Properties;
import java.util.Random;

public class ExperimentConfiguration {
	private String randomSeed;
	private double periodLengthInSeconds;
	private int periodsToRun;
	/**
	 * When processing messages coming or going to a single node in a given 
	 * period, this determines how many bytes are sent at one time before moving
	 * onto the next message.  This byte count is decremented from the nodes 
	 * bandwidth allocation for the given period.  When all messages have been 
	 * processed, the process begins again until no message can make process or
	 * the time period is up.
	 */
	private int bandwidthProcessingChunk;
	/**
	 * This determines what type of test we are running.  Valid values are 
	 * limited to Mixed and DhtOnly.  At a very abstract level, this only 
	 * effects what type of data request transactions are created.  For Mixed, 
	 * transactions that check clusters, and caching and the link are made.  For
	 * DhtOnly, requests are just single messages direct to the one single 
	 * source.
	 */
	private TestType testType;
	/**
	 * This determines the ratio of data reading operation and writing operation
	 */
	private double writingReadingRatio;
	private double partialUpdateRatio;
	
	public ExperimentConfiguration (Properties properties)
	throws DseException 
	{
		randomSeed = properties.getProperty("seed");
		
		if (properties.getProperty("period-length") == null)
			throw new DseException (
					"Required parameter 'period-length' not found (see " +
					"configuration)."
					);
		periodLengthInSeconds = 
			Double.parseDouble(properties.getProperty("period-length").trim());
		
		if (properties.getProperty("periods-to-run") == null)
			throw new DseException (
					"Required parameter 'periods-to-run' not found (see " +
					"configuration)."
					);
		periodsToRun = 
			Integer.parseInt(properties.getProperty("periods-to-run").trim())
				+ Experiment.AdditionalPeriodsToFinish;
	
		if (properties.getProperty("bandwidth-processing-chunk") == null)
			bandwidthProcessingChunk = 20000;
		else
			bandwidthProcessingChunk = 
				Integer.parseInt(
						properties.getProperty("bandwidth-processing-chunk").
							trim()
						);
		
		if (properties.getProperty("test-type") == null)
			testType = TestType.Mixed;
		else if (properties.getProperty("test-type").equals("dht-only"))
			testType = TestType.DhtOnly;
		else if (properties.getProperty("test-type").equals("mixed"))
			testType = TestType.Mixed;
		else if (properties.getProperty("test-type").equals("mixed-no-shares"))
			testType = TestType.MixedWithoutShares;
		else if(properties.getProperty("test-type").equals("dht-with-shares"))
			testType = TestType.DhtWithShares;
		else if(properties.getProperty("test-type").equals("cluster-with-shares"))
			testType = TestType.ClusterWithShares;
		else if(properties.getProperty("test-type").equals("dvs"))
			testType = TestType.DVS;
		else if(properties.getProperty("test-type").equals("uvn"))
			testType = TestType.UVN;
		else if(properties.getProperty("test-type").equals("dht-share-with-version3"))
			testType = TestType.DhtShareWithVersion3;
		else if(properties.getProperty("test-type").equals("two-level-dht-share"))
			testType = TestType.TwoLevelDhtShare;
		else if(properties.getProperty("test-type").equals("quorum-share"))
			testType = TestType.QuorumShare;
		else if(properties.getProperty("test-type").equals("single-version"))
			testType = TestType.SingleVersion;
		else if(properties.getProperty("test-type").equals("vnf"))
			testType = TestType.VNF;
		else if(properties.getProperty("test-type").equals("orp"))
			testType = TestType.ORP;
		else if(properties.getProperty("test-type").equals("dht-share-rep"))
			testType = TestType.DhtShareRep;
		else if(properties.getProperty("test-type").equals("pasis"))
			testType = TestType.DhtPasis;
		else if(properties.getProperty("test-type").equals("tla"))
			testType = TestType.TLA;
		else if(properties.getProperty("test-type").equals("dht-share-cvs"))
			testType = TestType.GDhtCVS;
		else if(properties.getProperty("test-type").equals("nsr"))
			testType = TestType.NSR;
		else if(properties.getProperty("test-type").equals("avid"))
			testType = TestType.AVID;
		else if(properties.getProperty("test-type").equals("hen07"))
			testType = TestType.HEN07;
		else
			throw new DseException (
					"Unknown 'test-type' value: " + 
					properties.getProperty("test-type") + "."
					);
		
		if(properties.getProperty("writing-reading-ratio") == null)
			writingReadingRatio = 0.2;
		else
			writingReadingRatio = Double.parseDouble(
					properties.getProperty("writing-reading-ratio").trim()
					);
		if(properties.getProperty("partial-update-ratio") == null)
			partialUpdateRatio = 0.0001;
		else
			partialUpdateRatio = Double.parseDouble(
					properties.getProperty("partial-update-ratio").trim()
					);
	}
	
	/**
	 * Returns a new random number generator for use in this experiment.
	 * @return	A random number generator.
	 */
	public Random getRandom () { 
		if (randomSeed == null)
			return new Random();
		return new Random(Integer.parseInt(randomSeed));		
	}
	/**
	 * Returns period length in seconds.
	 * @return	Period length in seconds.
	 */
	public double getTimePeriodLength () { return periodLengthInSeconds; }
	/**
	 * Returns the number of periods to simulate while running the experiment.
	 * @return	The number of periods to simulate.
	 */
	public int getNumberOfPeriodsToRun () { return periodsToRun; }
	/**
	 * Gets the number of bytes to process messages with at a time.
	 * @return
	 */
	public int getBandwidthProcessingChunk () { 
		return bandwidthProcessingChunk;
	}
	/**
	 * Gets the type of test we are running.  Mixed or DhtOnly.
	 * @return
	 */
	public TestType getTestType () { return testType; }
	
	public double getWritingReadingRatio() {return writingReadingRatio;}
	
	public double getPartialUpdateRatio() {return partialUpdateRatio;}
}
